#ifndef AST_DECLARATIONFUNCTION
#define AST_DECLARATIONFUNCTION
#include <string>
#include <list>
#include "node.h"

namespace AST {

    /**
     * Declaração de Função
     *
     * Estrutura necessária para armazenar informações de declaração de funções.
     * Para criação precisamos de um identificador para a declaração, juntamente
     * com os parâmetros em formato de conjunto de atributos; também precisamos
     * de tipagem de dados para retorno e o bloco de execução deste.
     *
     * @category AST
     * @package  AST
     */
    class DeclarationFunction : public Node {

    private:

        /**
         * Tipagem de Retorno
         */
        Node* _type;

        /**
         * Identificador de Declaração
         */
        std::string* _identifier;

        /**
         * Atributos para Chamada
         */
        std::list<AST::Node*>* _attributes;

        /**
         * Bloco de Comandos para Execução
         */
        Node* _block;

        /**
         * Configuração de Tipo de Retorno
         *
         * Método responsável pela configuração do tipo de retorno que é
         * utilizado pela função. Este tipo pode ser configurado como tipo
         * definido ou tipo vazio.
         *
         * @param  Node* Elemento para Configuração
         * @return Próprio Objeto para Encadeamento
         */
        DeclarationFunction* _setType(Node*);

        /**
         * Configuração de Identificador
         *
         * Método responsável pela configuração do identificador da função no
         * programa, sendo que este deve ser marcado futuramente na tabela de
         * símbolos do compilador.
         *
         * @param  std::string* Valor para Configuração
         * @return Próprio Objeto para Encadeamento
         */
        DeclarationFunction* _setIdentifier(std::string*);

        /**
         * Configuração de Atributos
         *
         * Método responsável pela configuração do conjunto de atributos que são
         * apresentados durante a definição da função. Caso a função declarada
         * não estiver sendo apresentada com atributos, este conjunto será
         * apresentado durante as configurações com valor vazio.
         *
         * @param  std::list<AST::Node*>* Elemento para Configuração
         * @return Próprio Objeto para Encadeamento
         */
        DeclarationFunction* _setAttributes(std::list<AST::Node*>*);

        /**
         * Configuração de Bloco de Execução
         *
         * Método responsável pela configuração do bloco de execução da função,
         * onde este utiliza um conjunto de comandos que são utilizados para as
         * variáveis do escopo; um destes deve possuir um retorno relacionado
         * com a tipagem definida na função, verificado na análise semântica.
         *
         * @param  Node* Elemento para Configuração
         * @return Próprio Objeto para Encadeamento
         */
        DeclarationFunction* _setBlock(Node*);

    public:

        /**
         * Construtor
         *
         * Estrutura utilizada para inicialização de objetos que definem funções
         * na linguagem, recebendo como parâmetros os responsáveis pela tipagem
         * de retorno, identificador da função no programa, conjunto de
         * atributos definidos e bloco de comandos utilizados.
         *
         * @param  std::string* Identificador da Função no Programa
         * @param  Node* Bloco de Comandos Utilizados
         * @param  std::list<AST::Node*>* Conjunto de Atributos
         * @param  Node* Tipagem de Retorno
         */
        DeclarationFunction(std::string*, Node*, std::list<AST::Node*>*, Node*);

        /**
         * Construtor Simples
         *
         * A declaração de função pode não possuir atributos ou tipagem de
         * retorno, sendo omitida neste construtor.
         *
         * @param  std::string* Identificador da Função no Programa
         * @param  Node* Bloco de Comandos Utilizados
         */
        DeclarationFunction(std::string*, Node*);

        /**
         * Construtor com Atributos e sem Retorno Tipado
         *
         * Declaração de função com os devidos atributos definidos, porém sem
         * tipagem de retorno, sendo considerada vazia.
         *
         * @param  std::string* Identificador da Função no Programa
         * @param  Node* Bloco de Comandos Utilizados
         * @param  std::list<AST::Node*>* Conjunto de Atributos
         */
        DeclarationFunction(std::string*, Node*, std::list<AST::Node*>*);

        /**
         * Construtor sem Atributos e com Retorno Tipado
         *
         * Declaração de função com a tipagem de retorno concluída com sucesso,
         * porém sem atributos definidos, sendo estes omitidos.
         *
         * @param  std::string* Identificador da Função no Programa
         * @param  Node* Bloco de Comandos Utilizados
         * @param  Node* Tipagem de Retorno
         */
        DeclarationFunction(std::string*, Node*, Node*);

        /**
         * Apresentação de Tipagem de Retorno
         *
         * Elemento representante do tipo de retorno utilizado pela função,
         * especificado no momento da definição. Este tipo também pode ser
         * considerado vazio, porém irá trabalhar da mesma forma que outros
         * tipos básicos da linguagem.
         *
         * @return Elemento Solicitado
         */
        Node* getType();

        /**
         * Apresentação de Identificador da Declaração
         *
         * Valor responsável pela identificação da função no programa, que deve
         * ser armazenado na tabela de símbolos do compilador quando criado.
         * Este identificador deve ser único; portanto deve ser verificado no
         * momento da análise semântica.
         *
         * @return Valor Solicitado
         */
        std::string* getIdentifier();

        /**
         * Apresentação do Conjunto de Atributos Definidos na Função
         *
         * Conjunto de declarações de variáveis utilizadas como atributos de
         * entrada para a função. Estes são necessários sempre que a função é
         * chamada no código, incluindo seus tipos.
         *
         * @return std::list<AST::Node*>* Elemento Solicitado
         */
        std::list<AST::Node*>* getAttributes();

        /**
         * Apresentação do Bloco de Comandos
         *
         * Elementos utilizados como blocos de comandos internos à declaração da
         * função. Estes comandos trabalham no escopo da função, utilizando
         * variáveis acessíveis daquele escopo.
         *
         * @return Elementos Solicitados
         */
        Node* getBlock();

        // Sobrescrita
        std::string toString(int);

    };

};

#endif

